﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Bluetooth.GenericAttributeProfile;

namespace bleCore
{
    public static class DeviceManager
    {
        static IEnumerable<ClientConfig> clientConfigs;
        static List<MyBleDevice> onLineClients = new List<MyBleDevice>();
        static BluetoothLEAdvertisementWatcher watcher = new BluetoothLEAdvertisementWatcher();
        public static event DeviceDiscoveryEvent DeviceDiscovery;
        public static event BleDiscoveryFinished BleDiscoveryFinished;
        public static event DataReceivedEvent BleDataReceived;

        public static void Discovery(IEnumerable<ClientConfig> regConfigs)
        {
            if (watcher.Status == BluetoothLEAdvertisementWatcherStatus.Started
                ||watcher.Status== BluetoothLEAdvertisementWatcherStatus.Stopping)
            {
                Logger.LogDevice("发现程序仍在运行");
                return;
            }
            Logger.LogDevice("启动BLE发现程序");
            clientConfigs = regConfigs;
            watcher.ScanningMode = BluetoothLEScanningMode.Active;
            watcher.SignalStrengthFilter.InRangeThresholdInDBm = -80;
            watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -90;
            watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
            watcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);
            watcher.Received += onDiscovery;
            watcher.Start();
        }
        static object locker = new object();
        private static async void onDiscovery(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
        {
            string mac_as_string = Utility.MAC2String(args.BluetoothAddress);
            var client = clientConfigs.FirstOrDefault(r => mac_as_string == r.MAC.ToLower());
            if (client == null) return;
            var device = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
            if (device != null)
            {
                var uuid = new Guid[client.GATT_LIST.Length];
                for (int i = 0; i < client.GATT_LIST.Length; i++)
                {
                    uuid[i] = new Guid(client.GATT_LIST[i]);
                }
                MyBleDevice myDev = null;
                lock (locker)
                {
                    var isOnLine = onLineClients.FirstOrDefault(r => r.MAC == client.MAC);
                    if (isOnLine != null) return;
                    myDev = new MyBleDevice(device, uuid);
                    myDev.ConnectLost += MyDev_ConnectLost;
                    Logger.LogDevice("发现有效设备{0}", mac_as_string);
                    onLineClients.Add(myDev);
                    myDev.DataRecieved += DataReceived;
                }
                if (myDev!=null && DeviceDiscovery != null)
                {
                    foreach (var handler in DeviceDiscovery.GetInvocationList())
                    {
                        ((DeviceDiscoveryEvent)handler).Invoke(myDev);
                    }
                }
                
            }
            if (onLineClients.Count() == clientConfigs.Count())
            {
                sender.Stop();
                if (BleDiscoveryFinished != null)
                {
                    foreach (var handler in BleDiscoveryFinished.GetInvocationList())
                    {
                        ((BleDiscoveryFinished)handler).Invoke();
                    }
                }
            }
        }

        static void MyDev_ConnectLost(MyBleDevice _device)
        {
            onLineClients.Remove(_device);
            if (watcher.Status != BluetoothLEAdvertisementWatcherStatus.Started)
            {
                watcher.Start();
            }
        }

        static void DataReceived(MyBleDevice _device, GattCharacteristic sender, byte[] data)
        {
            if (BleDataReceived != null)
            {
                var receivers = BleDataReceived.GetInvocationList();
                foreach (var receiver in receivers)
                {
                    ((DataReceivedEvent)receiver).Invoke(_device, sender, data);
                }
            }
        }

        public static void Stop()
        {
            watcher.Stop();
        }

        public static List<MyBleDevice> GetOnLineClients() 
        {
            return onLineClients;
        }
    }
}
